package com.zhiyi.xppay.hook;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.text.TextUtils;

import com.zhiyi.item.CpReqData;
import com.zhiyi.xppay.consts.AppConst;
import com.zhiyi.xppay.ui.MainActivity;
import com.zhiyi.xppay.utils.DBManager;
import com.zhiyi.xppay.utils.L;
import com.zhiyi.xppay.utils.PayHelperUtils;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by pc_mg on 2018/12/28.
 */

public class CloudPayHook {
    private static ClassLoader mClassloader;
    private static Activity mActivity;
    public static String encvirtualCardNo;
    public static Long time;

    private static DBManager dbManager;
    private static long lastUptime;

    public static boolean YSF_PACKAGE_ISHOOK = false;
    public static boolean MAINPAGE = false;


    public class CloundPayReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(AppConst.CP_QRCODE)) {
                L.d("生产云闪付二维码");

                Intent intent1 = new Intent(context,XposedHelpers.findClass("com.unionpay.activity.UPActivityMain",context.getClassLoader()));
                intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent1);

                String money = intent.getStringExtra("money");
                String mark = intent.getStringExtra("mark");
                if (money == null) {
                    money = "0.01";
                }
                if (mark == null) {
                    mark = "测试";
                }
                final Activity activity = (Activity) context;
                BuildQRcode(activity, money, mark);
            } else if (intent.getAction().equals(AppConst.CP_GETPAYER)) {
                String orderid = intent.getStringExtra("orderid");
                CloudPayHook.startGetPayer("mark", orderid);
            } else if (intent.getAction().equals(AppConst.CP_LOGIN)) {
                CloudPayHook.Login();
            }else if (intent.getAction().equals(MainActivity.autocheckOrder)){
                /*if(!MAINPAGE){
                    Intent intent1 = new Intent(context, XposedHelpers.findClass("com.unionpay.activity.UPActivityMain", context.getClassLoader()));
                    intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(intent1);
                    MAINPAGE = true;
                }else{
                    Intent intent1 = new Intent(context, XposedHelpers.findClass("com.unionpay.activity.mine.UPActivityMine", context.getClassLoader()));
                    intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(intent1);
                    MAINPAGE = false;
                }*/
            }
        }
    }


    public void hook(final ClassLoader classLoader, final Context context) {
        mClassloader = classLoader;
        lastUptime = System.currentTimeMillis();
        XposedHelpers.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                Bundle bundle = (Bundle) param.args[0];
                if (param.thisObject.getClass().toString().contains("com.unionpay.activity.UPActivityMain")
                        && !YSF_PACKAGE_ISHOOK) {
                    L.log("云闪付 hook UPActivityMain成功");
                    L.d("云闪付 hook 成功");
                    PayHelperUtils.sendmsg(context, "云闪付hook成功");

                    YSF_PACKAGE_ISHOOK = true;
                    Context context = (Context) param.thisObject;
                    mActivity = (Activity) context;
                    //
                    IntentFilter filter = new IntentFilter();
                    filter.addAction(AppConst.CP_QRCODE);
                    filter.addAction(AppConst.CP_GETPAYER);
                    filter.addAction(AppConst.CP_LOGIN);
                    filter.addAction(MainActivity.autocheckOrder);
                    context.registerReceiver(new CloundPayReceiver(), filter);

                }
                super.afterHookedMethod(param);
            }
        });
    }

    public static String CheckNewOrder(Activity activity) {
        try {
            String str2 = "https://wallet.95516.com/app/inApp/order/list?currentPage="
                    + Enc("1", mClassloader)
                    + "&month=" + Enc("0", mClassloader)
                    + "&orderStatus=" + Enc("0", mClassloader)
                    + "&orderType=" + Enc("A30000", mClassloader)
                    + "&pageSize=" + Enc("10", mClassloader) + "";
            OkHttpClient client = null;
            OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
            builder.connectTimeout(50, TimeUnit.SECONDS);
            builder.writeTimeout(50, TimeUnit.SECONDS);
            builder.readTimeout(50, TimeUnit.SECONDS);
            client = builder.build();
            Request request = new Request.Builder()
                    .url(str2)
                    .header("X-Tingyun-Id", getXTid(mClassloader))
                    .header("X-Tingyun-Lib-Type-N-ST", "0;" + System.currentTimeMillis())
                    .header("sid", getSid(mClassloader))
                    .header("urid", geturid(mClassloader, activity))
                    .header("cityCd", getcityCd(mClassloader))
                    .header("locale", "zh-CN")
                    .header("User-Agent", "Android CHSP")
                    .header("dfpSessionId", getDfpSessionId(mClassloader))
                    .header("gray", getgray(mClassloader))
                    .header("Accept", "*/*")
                    .header("key_session_id", "")
                    .header("Host", "wallet.95516.com")
                    .build();
            Response response = client.newCall(request).execute();

            String RSP = response.body().string();
            String DecRsp = Dec(RSP, mClassloader);
            L.d("CheckNewOrder str2=>" + str2 + " DecRSP=>" + DecRsp);
            if (DecRsp != null) {
                //这里有很多笔，可以自己调整同步逻辑s
                JSONArray o = new JSONObject(DecRsp).getJSONObject("params").getJSONArray("uporders");
                boolean find = false;
                String mrt = "";
                for (int i = 0; i < o.length(); i++) {
                    JSONObject p = o.getJSONObject(i);
                    String orderid = p.getString("orderId");
                    if (isNewOrder(orderid)) {
                        String rt = DoOrderInfoGet(orderid, activity);
                        if (rt != null && rt.length() > 1) {
                            L.log(rt);
                            mrt += rt;
                        }
                        find = true;
                    }
                }
                if (find) {
                    return mrt;
                }
            } else {
                L.log("云闪付请求到的数据为空");
            }
            return "NO_MATCH_ORDER";
        } catch (Throwable e) {
            L.log(e.getMessage());
            return "ERR:" + e.getLocalizedMessage();
        }
    }

    private static boolean isNewOrder(String orderid) {
        boolean isex = dbManager.isExistCPOrder(orderid);
        return !isex;
    }

    private static void compReq(String remark, String orderid) {
        for (CpReqData req : reqlist) {
            if (req.remark().equals(remark)) {
                req.status = CpReqData.Status_Comp;
                break;
            }
        }
        // 添加数据库
        ArrayList<CpReqData> datas = dbManager.FindCPOrder("");
        if (datas != null) {
            for (CpReqData req : reqlist) {
                if (req.remark().equals(remark)) {
                    req.orderid = orderid;
                    dbManager.updateCPOrder(req);
                } else {
                    L.d("不在本地数据库的订单：" + remark + " orderid " + orderid);
                    CpReqData data = new CpReqData(remark);
                    data.orderid = orderid;
                    dbManager.addCPOrder(data);
                }
            }
        }
    }

    private static String DoOrderInfoGet(String orderid, Activity activity) {
        if (orderid.length() > 5) {
            L.d("查询订单详情" + orderid);
            try {
                String args = "{\"orderType\":\"21\",\"transTp\":\"simple\",\"orderId\":\"" + orderid + "\"}";
                String str2 = "https://wallet.95516.com/app/inApp/order/detail";
                L.log("获取订单详情：" + orderid + " =》 " + str2);
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        .url(str2)
                        .header("X-Tingyun-Id", getXTid(mClassloader))
                        .header("X-Tingyun-Lib-Type-N-ST", "0;" + System.currentTimeMillis())
                        .header("sid", getSid(mClassloader))
                        .header("urid", geturid(mClassloader, activity))
                        .header("cityCd", getcityCd(mClassloader))
                        .header("locale", "zh-CN")
                        .header("User-Agent", "Android CHSP")
                        .header("dfpSessionId", getDfpSessionId(mClassloader))
                        .header("gray", getgray(mClassloader))
                        .header("Accept", "*/*")
                        .header("key_session_id", "")
                        .header("Content-Type", "application/json; charset=utf-8")
                        .header("Host", "wallet.95516.com")
                        .post(RequestBody.create(null, Enc(args, mClassloader)))
                        .build();
                Response response = client.newCall(request).execute();
                String RSP = response.body().string();
                String DecRsp = Dec(RSP, mClassloader);
                //这里有很多笔，可以自己调整同步逻辑s
                JSONObject params = new JSONObject(DecRsp).getJSONObject("params");
                L.d("云闪付详情数据===>" + params.toString());
                String orderDetail = params.getString("orderDetail");
                JSONObject o = new JSONObject(orderDetail);
                String u = o.getString("payUserName");
                String mark = o.getString("postScript");
                String totalAmount = params.getString("totalAmount");
                String walletOrderid = params.getString("orderId");
                walletOrderid = walletOrderid.replaceAll(" ", "");
                String dt = params.getString("orderTime");
                dt = PayHelperUtils.dateToStamp(dt, "yyyy-MM-dd HH:mm:ss");
                float f = Float.parseFloat(totalAmount) / 100;
                totalAmount = "" + f;
                //
                Intent broadCastIntent = new Intent();
                broadCastIntent.putExtra("bill_no", walletOrderid);//orderid
                broadCastIntent.putExtra("bill_money", totalAmount);
                broadCastIntent.putExtra("bill_mark", mark);
                broadCastIntent.putExtra("bill_type", AppConst.TYPE_CPPAY);
                //
                broadCastIntent.putExtra("bill_payer", u);
                broadCastIntent.putExtra("bill_dt", dt);
                //
                broadCastIntent.setAction(AppConst.BILLRECEIVED_ACTION);
                getContext().sendBroadcast(broadCastIntent);
                compReq(mark, orderid);
                return "";
            } catch (Throwable e) {
                XposedBridge.log(e);
                return "ERR:" + e.getLocalizedMessage();
            }
        } else {
            return "ERROR_ORDER:" + orderid;
        }
    }

    private static void getVirtualCardNum(Activity activity, final GetVirCardListener listener) { // E99A1E717BAEFDAE F2E42D325BC2AE7E
        try {
            final String str2 = "https://pay.95516.com/pay-web/restlet/qr/p2pPay/getInitInfo?cardNo=&cityCode=" + Enc(getcityCd(mClassloader), mClassloader);
            cpRequest(str2, activity, new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    XposedBridge.log(e);
                    listener.error(e.getMessage());
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String RSP = response.body().string();
                    String Rsp = Dec(RSP, mClassloader);
                    if (Rsp == null) {
                        if (listener != null) {
                            listener.error("数据为空");
                        }
                    } else {
                        try {
                            String encvirtualCardNo = Enc(new JSONObject(Rsp).getJSONObject("params").getJSONArray("cardList").getJSONObject(0).getString("virtualCardNo"), mClassloader);
                            if (listener != null) {
                                listener.success(encvirtualCardNo);
                            }
                        } catch (Throwable e) {
                            XposedBridge.log(e);
                            if (listener != null) {
                                listener.error(e.getMessage());
                            }
                        }
                    }
                }
            });
        } catch (Throwable e) {
            XposedBridge.log(e);
        }

    }

    public static void GenQrCode(final Activity activity, final String money, final String mark, String encvirtualCardNo) {
        L.d("生成收款二维码------");
        if (System.currentTimeMillis() - lastUptime > 1200000) {
            lastUptime = System.currentTimeMillis();
            PayHelperUtils.startAppCP(getContext());
        }
        try {
            //
            String mark1 = mark;
            String money1 = new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).toPlainString().replace(".", "");
            final String str2 = "https://pay.95516.com/pay-web/restlet/qr/p2pPay/applyQrCode?txnAmt="
                    + Enc(money1, mClassloader) + "&cityCode=" + Enc(getcityCd(mClassloader), mClassloader) + "&comments=" + Enc(mark1, mClassloader) + "&virtualCardNo=" + encvirtualCardNo;
            cpRequest(str2, activity, new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    L.log("云闪付生成二维码失败");
                    PayHelperUtils.startAppCP(getContext());
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String RSP = response.body().string();
                    String Rsp = Dec(RSP, mClassloader);
                    try {
                        JSONObject o = new JSONObject(Rsp);
                        o.put("mark", mark);
                        o.put("money", money);
                        final String orderid = o.getJSONObject("params").getString("orderId");
                        String payurl = o.getJSONObject("params").getString("certificate");
                        Intent broadCastIntent = new Intent();
                        broadCastIntent.putExtra("money", money);
                        broadCastIntent.putExtra("mark", mark);
                        broadCastIntent.putExtra("type", AppConst.TYPE_CPPAY);
                        broadCastIntent.putExtra("payurl", payurl);
                        broadCastIntent.putExtra("img_url", orderid);
                        broadCastIntent.setAction(AppConst.QRCODERECEIVED_ACTION);
                        getContext().sendBroadcast(broadCastIntent);
                        if (dbManager == null) {
                            dbManager = new DBManager(activity);
                        }
                        startGetPayer(mark, orderid);
                    } catch (Throwable e) {
                        XposedBridge.log(e);
                    }
                }
            });
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
    }

    private static Thread thread;

    public static void startGetPayer(String remark, String orderid) {
        CpReqData data = new CpReqData(remark);
        if (reqlist == null) {
            reqlist = new LinkedList<>();
        }
        data.orderid = orderid;
        data.time = "" + (System.currentTimeMillis() / 1000);
        L.d("插入云闪付订单到数据库" + orderid);
        dbManager.addCPOrder(data);
        addLast(data);
        if (thread == null || !thread.isAlive()) {
            L.log("轮询线程启动~！！！！！！！！！！！！！！！！！！！！");
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    CloudPayHook.run();
                }
            });
            thread.start();
        }
    }

    private static String Dec(String src, ClassLoader mClassLoader) {
        try {
            return (String) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.unionpay.encrypt.IJniInterface", mClassLoader), "decryptMsg", src);
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
        return "";
    }

    private static String Enc(String src, ClassLoader mClassLoader) {
        try {
            return (String) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.unionpay.encrypt.IJniInterface", mClassLoader), "encryptMsg", src);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return "";
    }

    private static String getXTid(ClassLoader mClassLoader) {
        try {
            Class m_s = XposedHelpers.findClass("com.networkbench.agent.impl.m.s", mClassLoader);
            Object f = XposedHelpers.callStaticMethod(m_s, "f");
            Object h = XposedHelpers.callMethod(f, "H");
            Object i = XposedHelpers.callStaticMethod(m_s, "I");

            String xtid = m_s.getDeclaredMethod("a", String.class, int.class).invoke(null, h, i).toString();
            return xtid;
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
        return null;
    }

    private static String getSid(ClassLoader mClassLoader) {
        String sid = "";
        try {
            Object b = XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.unionpay.network.aa", mClassLoader), "b");
            sid = XposedHelpers.callMethod(b, "e").toString();
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
//        XposedBridge.log("sid:" + sid + "");
        return sid;
    }

    private static String geturid(ClassLoader mClassLoader, Activity activity) {
        String Cacheurid = "";
        try {
            Class data_d = XposedHelpers.findClass("com.unionpay.data.d", mClassLoader);
            Object o = XposedHelpers.callStaticMethod(data_d, "a", new Class[]{Context.class}, new Object[]{activity});
            Object o_A = XposedHelpers.callMethod(o, "A");
            if (o_A == null) {
                PayHelperUtils.sendmsg(getContext(), "请登录云闪付后重试");
            } else {
                String v1_2 = XposedHelpers.callMethod(XposedHelpers.callMethod(o, "A"), "getHashUserId").toString();
                if (!TextUtils.isEmpty(v1_2) && v1_2.length() >= 15) {
                    Cacheurid = v1_2.substring(v1_2.length() - 15);
                }
            }
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
        return Cacheurid;
    }

    private static String getDfpSessionId(ClassLoader mClassLoader) {
        String CacheDfpSessionId = "";
        try {
            Object o = XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.unionpay.service.b", mClassLoader), "d");
            CacheDfpSessionId = o.toString();
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
        return CacheDfpSessionId;
    }

    private static String getcityCd(ClassLoader mClassLoader) {
        String CachecityCd = "";
        try {
            CachecityCd = XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.unionpay.location.a", mClassLoader), "i").toString();
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
        return CachecityCd;
    }

    private static String getgray(ClassLoader mClassLoader) {
        String Cachegray = "";
        try {
            Object b = XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.unionpay.network.aa", mClassLoader), "b");
            Cachegray = XposedHelpers.callMethod(b, "d").toString();
        } catch (Throwable e) {
            XposedBridge.log(e);
        }
        return Cachegray;
    }

    private static void cpRequest(String url, Activity activity, Callback callback) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .header("X-Tingyun-Id", getXTid(mClassloader))
                .header("X-Tingyun-Lib-Type-N-ST", "0;" + System.currentTimeMillis())
                .header("sid", getSid(mClassloader))
                .header("urid", geturid(mClassloader, activity))
                .header("cityCd", getcityCd(mClassloader))
                .header("locale", "zh-CN")
                .header("User-Agent", "Android CHSP")
                .header("dfpSessionId", getDfpSessionId(mClassloader))
                .header("gray", getgray(mClassloader))
                .header("key_session_id", "")
                .header("Host", "pay.95516.com")
                .build();
        client.newCall(request).enqueue(callback);
    }

    public static Context getContext() {
        try {
            Class<?> ActivityThread =
                    Class.forName("android.app.ActivityThread");

            Method method = ActivityThread.getMethod("currentActivityThread");
            Object currentActivityThread = method.invoke(ActivityThread);//获取currentActivityThread 对象
            Method method2 = currentActivityThread.getClass().getMethod("getApplication");
            return (Context) method2.invoke(currentActivityThread);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void Login() {
        String loginid = geturid(mClassloader, mActivity);
        PayHelperUtils.sendLoginId(loginid, AppConst.TYPE_CPPAY, getContext());
    }

    public static void BuildQRcode(final Activity activity, final String money, final String mark) {
        getVirtualCardNum(activity, new GetVirCardListener() {
            @Override
            public void success(String re) {
                encvirtualCardNo = re;
                time = System.currentTimeMillis();
                GenQrCode(activity, money, mark, re);
            }

            @Override
            public void error(String error) {
                PayHelperUtils.sendmsg(activity, "云闪付生成二维码异常");
                L.log("云闪付生成二维码异常" + error);
            }
        });
    }

    private static LinkedList<CpReqData> reqlist;

    public static void addLast(CpReqData data) {
        for (CpReqData _data : reqlist) {
            if (_data.remark().equals(data.remark())) {
                return;
            }
        }
        reqlist.add(data);
    }

    public static void run() {
        do {
            try {
                Thread.sleep(7000);
                if (reqlist.isEmpty()) {
                    continue;
                }
//                String oid = null;
                for (Iterator<CpReqData> item = reqlist.iterator(); item.hasNext(); ) {
                    CpReqData data = item.next();
                    if (data.times > 60 || data.status == CpReqData.Status_Comp) {
                        item.remove();
                        continue;
                    }
//                    if (data.status == CpReqData.Status_Error) {
                    data.times++;
//                    }
//                    oid = data.orderid;
                }
                int size = reqlist.size();

                L.d("待验证订单数量--->" + size);

                if (size > 0) {
                    CheckNewOrder(mActivity);
                }
            } catch (Throwable t) {
                XposedBridge.log(t);
            }
        }
        while (true);
    }

}

